<?php
/**
 * Created by PhpStorm.
 * User: shooke
 * Date: 17-2-15
 * Time: 上午10:30
 */

namespace corephp\route;



class Route implements RouteInterface
{
    const ROUTE_TYPE_PATHINFO = 'PATHINFO';
    const ROUTE_TYPE_PARAM = 'param';
    /**
     * 默认要执行的控制器方法
     * @var string
     */
    public $defaultRoute = 'site/index';

    /**
     * 路由规则
     * [
     * ['route'=>'view/(.*)','run'=>'class/action','method'=>'get|post']
     * ]
     * @var array
     */
    public $rules;
    /**
     * 是否隐藏执行文件
     * @var bool
     */
    public $hiddenScriptFile = true;
    /**
     * 路由形式
     * pathinfo 或 param
     * @var string
     */
    public $routeType = 'pathinfo';
    /**
     * 路由接收参数
     * @var string
     */
    public $routeParamName = 'r';


    /**
     * 获取请求方式
     * @return mixed
     */
    private function _method()
    {
        return $_SERVER['REQUEST_METHOD'];
    }


    /**
     * 根据规则解析路由
     * @return array
     */
    private function _parseRule()
    {
        $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
        $method = $this->_method();
        $route = '';//控制器方法
        $arguments = [];//参数
        foreach ($this->rules as $rule) {
            //验证路由规则
            if (preg_match('#' . $rule['route'] . '#', $uri, $matches)) {
                //验证请求方式
                if (isset($rule['method']) && preg_match("/$method/i", $rule['method'])) {
                    $route = $rule['run'];
                    array_shift($matches);//移除完整匹配保留参数
                    $arguments = $matches;
                    break;
                }
            }
        }
        return [
            'route'     => $route,
            'arguments' => $arguments
        ];
    }

    /**
     * 普通形式解析路由
     * @return array
     */
    private function _parseUrlString()
    {
        isset($_SERVER['QUERY_STRING']) ? parse_str($_SERVER['QUERY_STRING'], $paramArray) : parse_str(parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY), $paramArray);
        $call = [];
        if (isset($paramArray[$this->routeParamName])) {
            $call['route'] = $paramArray[$this->routeParamName];
            unset($paramArray[$this->routeParamName]);
            $call['arguments'] = $paramArray;
        } else {
            $call = [
                'route'     => '',
                'arguments' => $paramArray
            ];
        }

        return $call;
    }

    /**
     * pathinfo形式解析路由
     * @return array
     */
    private function _parsePathinfo()
    {
        $route = isset($_SERVER['PATH_INFO']) ? $_SERVER['PATH_INFO'] : str_replace($_SERVER['SCRIPT_NAME'],'',$_SERVER['REQUEST_URI']);

        isset($_SERVER['QUERY_STRING']) ? parse_str($_SERVER['QUERY_STRING'], $paramArray) : parse_str(parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY), $paramArray);
        return [
            'route'     => $route,
            'arguments' => $paramArray
        ];
    }

    /**
     * 转换为分隔符间隔的字符串
     * @param $string
     * @param string $separ
     * @return mixed
     */
    private function _under($string, $separ = '-'){
        $temp_array = [];
        for($i=0;$i<strlen($string);$i++){
            $ascii_code = ord($string[$i]);
            if($ascii_code >= 65 && $ascii_code <= 90){
                if($i == 0){
                    $temp_array[] = chr($ascii_code + 32);
                }else{
                    $temp_array[] = $separ.chr($ascii_code + 32);
                }
            }else{
                $temp_array[] = $string[$i];
            }
        }
        return implode('',$temp_array);
    }

    /**
     * 转换为大驼峰
     * @param $string
     * @param string $separ
     * @return string
     */
    private function _bigCamel($string, $separ = '-')
    {
        //转换为小写
//        $string = strtolower($string);
        $output = '';
        $array = explode($separ, $string);
        foreach ($array as $val){
            $output .= ucfirst($val);
        }
        return $output;
    }

    /**
     * 转换位小驼峰命名
     * @param $string
     * @param string $separ
     * @return mixed
     */
    private function _littleCamel($string, $separ = '-')
    {
        //转换为大驼峰
        $output = $this->_bigCamel($string, $separ);
        //首字母转为小写
        return lcfirst($output);
    }
    /**
     * 执行中间件和控制器
     * @param $call
     * @return mixed
     */
    private function _format($call)
    {
        $className = $this->_bigCamel(dirname($call['route']));
        $action = $this->_littleCamel(basename($call['route']));
        return [
            'class'     => $className,
            'action'    => $action,
            'arguments' => $call['arguments']
        ];

    }

    /**
     * 解析路由
     * @return array 返回['class'=>$className, 'action'=>$action, 'arguments'=>$call['arguments']
     * ]
     */
    public function parse()
    {
        //根据规则操作路由
        if ($this->rules) {
            $call = $this->_parseRule();
            if ($call['route']) {
                return $this->_format($call);
            }
        }

        //解析规则外的规则
        switch (strtoupper($this->routeType)) {
            case self::ROUTE_TYPE_PATHINFO:
                $call = $this->_parsePathinfo();
                break;
            case self::ROUTE_TYPE_PARAM:
                $call = $this->_parseUrlString();
        }

        //如果路由为空或为斜杠（/）则使用默认路由
        if (empty($call['route']) || $call['route'] == '/') {
            $call['route'] = $this->defaultRoute;
        }

        return $this->_format($call);


    }

    /**
     * 生成url
     * @param $ctrlAction
     * @param array $param
     * @param string $anchor
     * @return string
     */
    public function createUrl($ctrlAction, $param = [], $anchor = '')
    {
        $scriptName = $_SERVER['SCRIPT_NAME'];
        $route = '';
        $url = '';
        if ($this->rules) {
            foreach ($this->rules as $rule) {
                if ($rule['run'] = $ctrlAction) {
                    $route = $rule['route'];
                    break;
                }
            }
            if ($route) {

            }
        }
        if ($route == '') {
            $route = $this->_under($ctrlAction);
            //解析规则外的规则
            switch (strtoupper($this->routeType)) {
                case self::ROUTE_TYPE_PATHINFO:
                    $url .= $this->hiddenScriptFile ? dirname($scriptName) . '/' . $route : $scriptName . '/' . $route;
                    $url .= '?' . http_build_query($param);
                    break;
                case self::ROUTE_TYPE_PARAM:
                    $urlParam = [$this->routeParamName => $route];
                    if ($param) {
                        foreach ($param as $key => $value) {
                            $urlParam[$key] = $value;
                        }
                    }
                    $url .= $this->hiddenScriptFile
                        ? dirname($scriptName) . '?' . http_build_query($urlParam)
                        : $scriptName . '?' . http_build_query($urlParam);

            }
        }
        $url .= $anchor ? '#' . $anchor : '';
        return $url;

    }

}